package com.hwtx.form.domain.handle;

import cn.hutool.extra.spring.SpringUtil;
import com.google.common.collect.Maps;
import com.hwtx.form.domain.def.meta.config.FormComponentConfig;
import com.hwtx.form.domain.service.CommonApiInvoker;
import com.hwtx.form.persistence.entity.ApiDef;
import com.hwtx.form.util.FormUtil;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;

import static com.hwtx.form.domain.FormConstants.DEFAULT_TABLE_NAME;

@Getter
@Builder
public class SelectItemsInfo {
    Map<String, List<SelectItemInfo>> tableItems;
    List<SelectItemInfo> noTableItems;
    Map<String, Map<String, String>> uniqueItems;

    public interface ComponentItemParser {
        List<String> updateFields(SelectItemInfo selectItemInfo, String table);

        Map<String, Object> updateValues(Map<String, Object> data, SelectItemInfo itemInfo, String table, ValueDefaultCallback valueDefaultCallback);

        Map<String, Map<String, String>> readFields(SelectItemInfo itemInfo);

        Map<String, Object> getInvokeValues(SelectItemInfo itemInfo, String code, Map<String, Object> inputValues);
    }

    public interface ValueDefaultCallback {
        Object getDefaultValue(String field);
    }

    public static class DefaultComponentItemParser implements ComponentItemParser {

        @Override
        public Map<String, Object> getInvokeValues(SelectItemInfo itemInfo, String code, Map<String, Object> inputValues) {
            ApiDef apiDef = FormUtil.getApiDef(code);
            CommonApiInvoker.InvokeData invokeData = SpringUtil.getBean(CommonApiInvoker.class).invokeApiNoCareTest(apiDef, inputValues, null);
            if (invokeData != null) {
                if (StringUtils.isNotBlank(apiDef.getExt())) {
                    Object extRet = invokeData.getRetData();
                    if (extRet instanceof Map) {
                        return (Map<String, Object>) extRet;
                    } else {
                        throw new RuntimeException("扩展程序调用需要返回Map格式");
                    }
                } else {
                    List<Map<String, Object>> ret = invokeData.getRet();
                    if (ret != null) {
                        return ret.getFirst();
                    } else {
                        throw new RuntimeException("调用模型接口返回集合返回多个值，ApiCode = " + code);
                    }
                }
            }
            return null;
        }

        @Override
        public List<String> updateFields(SelectItemInfo selectItemInfo, String table) {
            if (MapUtils.isNotEmpty(selectItemInfo.getAddFields())) {
                return selectItemInfo.getAddFields().get(table);
            }
            if (StringUtils.isNotBlank(selectItemInfo.getField())) {
                return List.of(selectItemInfo.getField());
            }
            return null;
        }

        @Override
        public Map<String, Object> updateValues(Map<String, Object> data, SelectItemInfo selectItemInfo, String table, ValueDefaultCallback valueDefaultCallback) {
            Object value = null;
            if (StringUtils.isNotBlank(selectItemInfo.getName())) {
                value = data.get(selectItemInfo.getName());
            }
            if (value == null) {
                value = data.get(selectItemInfo.getField());
            }
            if (MapUtils.isNotEmpty(selectItemInfo.getAddFields()) && value != null) {
                List<String> keys = selectItemInfo.getAddFields().get(table);
                List<Object> values = List.of(value.toString().split(","));
                if (CollectionUtils.isNotEmpty(keys) && CollectionUtils.isNotEmpty(values)) {
                    Map<String, Object> map = Maps.newHashMap();
                    for (int i = 0; i < keys.size(); i++) {
                        map.put(keys.get(i), values.get(i));
                    }
                    return map;
                }
                return Map.of();
            }
            if (value == null && valueDefaultCallback != null) {
                value = valueDefaultCallback.getDefaultValue(selectItemInfo.getField());
            }
            if (value == null) {
                return Map.of();
            }
            return Map.of(selectItemInfo.getField(), value);
        }

        @Override
        public Map<String, Map<String, String>> readFields(SelectItemInfo selectItemInfo) {
            if (MapUtils.isNotEmpty(selectItemInfo.getAddFields())) {
                Map<String, Map<String, String>> addFields = Maps.newHashMap();
                selectItemInfo.getAddFields().forEach((table, fields) -> addFields.compute(table, (key, value) -> {
                    if (value == null) {
                        value = Maps.newHashMap();
                    }
                    for (String field : fields) {
                        value.put(field, "");
                    }
                    return value;
                }));
                return addFields;
            }
            if (StringUtils.isNotBlank(selectItemInfo.getField())) {
                if (StringUtils.isNotBlank(selectItemInfo.getName())) {
                    return Map.of(DEFAULT_TABLE_NAME, Map.of(selectItemInfo.getField(), selectItemInfo.getName()));
                }
                return Map.of(DEFAULT_TABLE_NAME, Map.of(selectItemInfo.getField(), ""));
            }
            return Map.of();
        }
    }

    @Getter
    @Builder
    @EqualsAndHashCode(of = {"field"})
    @ToString(of = {"field", "name"})
    public static class SelectItemInfo {
        String field;
        String name;
        Map<String, List<String>> addFields;
        boolean isApiInvoke;
        boolean mask;
        Map<String, Object> comExt;
        FormComponentConfig formComponentConfig;
    }
}